import java.awt.Point;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;

public class Image implements Serializable {
	private static final long serialVersionUID = 1L;
	private int ySize, xSize;
	private HashMap<Point, Integer> coloredPoints;
	private ArrayList<Point> keys;
	private int backgroundColor;

	/**
	 * Constructor for Image
	 */
	public Image() {
		ySize = 100;
		xSize = 100;
		backgroundColor = 0;
		coloredPoints = new HashMap<Point, Integer>(50);
		keys = new ArrayList<Point>();
	}

	/**
	 * Constructor for Image with predefined size
	 * 
	 * @param size
	 *            Size of Component
	 */
	public Image(int ySize, int xSize) {
		this.ySize = ySize;
		this.xSize = xSize;
		backgroundColor = 0;
		coloredPoints = new HashMap<Point, Integer>(50);
		keys = new ArrayList<Point>();
	}

	/**
	 * Changes the y size of the component
	 * 
	 * @param size
	 */
	public void setySize(int size) {
		this.ySize = size;
	}
	
	/**
	 * Changes the x size of the component
	 * 
	 * @param size
	 */
	public void setxSize(int size) {
		this.xSize = size;
	}

	/**
	 * Used to find the y size of the Image
	 * 
	 * @return The size of the component
	 */
	public int getySize() {
		return ySize;
	}
	
	/**
	 * Used to find the x size of the Image
	 * 
	 * @return The size of the component
	 */
	public int getxSize() {
		return xSize;
	}

	/**
	 * Changes the color at a specified point
	 * 
	 * @param p
	 *            Point whose color has changed
	 * @param color
	 *            New color at Point p
	 */
	public void changeColor(Point p, int color) {
		if (!coloredPoints.containsKey(p)) {
			coloredPoints.put(p, color);
		} else if (coloredPoints.get(p) != color) {
			coloredPoints.remove(p);
			coloredPoints.put(p, color);
		}
	}

	/**
	 * Finds the color at a Point with position (x,y)
	 * 
	 * @param x
	 *            X-coordinate of Point
	 * @param y
	 *            Y-coordinate of Point
	 * @return The index of the color at a Point with position (x,y)
	 */
	public int getColorsAtPos(int x, int y) {
		if (coloredPoints.containsKey(new Point(x, y))) {
			return coloredPoints.get(new Point(x, y));
		} else {
			return backgroundColor;
		}
	}

	/**
	 * Rotates all the Points in the Image that are colored
	 */
	public void rotate() {
		HashMap<Point, Integer> oldColoredPoints = coloredPoints;
		coloredPoints = new HashMap<Point, Integer>(50);
		for (int i = 0; i < keys.size(); i++) {
			Point p = keys.get(i);
			int x = p.x - xSize / 2;
			int y = ySize / 2 - p.y;
			Point p1 = new Point(-y, x);
			p1.x = p1.x + xSize / 2;
			p1.y = xSize / 2 - p1.y;
			coloredPoints.put(p1, oldColoredPoints.get(p));
			keys.set(i, p1);
		}
	}

	/**
	 * 
	 * @return The current background color index
	 */
	public int getBackgroundColor() {
		return backgroundColor;
	}

	/**
	 * Changes all points to be unchanged from background color
	 */
	public void clearColoredPoints() {
		coloredPoints.clear();
		keys.clear();
	}

	/**
	 * Adds a Point and its color index to the image
	 * 
	 * @param p
	 *            Point at which the color has changed
	 * @param color
	 *            Color index to be added
	 */
	public void add(Point p, int color) {
		coloredPoints.put(p, color);
		keys.add(p);
	}

	/**
	 * 
	 * @return The keys for the coloredPoints HashMap (all colored Points)
	 */
	public ArrayList<Point> getKeys() {
		return keys;
	}

	/**
	 * Changes background color
	 * 
	 * @param color
	 *            New color of background
	 */
	public void setBackgroundColor(int color) {
		backgroundColor = color;
	}

	/**
	 * Removes a colored Point form the Image
	 * 
	 * @param p
	 *            Point to be removed
	 */
	public void remove(Point p) {
		coloredPoints.remove(p);
		keys.remove(p);
	}
}
